package com.ly.component.threadpool.util;

import com.ly.component.threadpool.callback.CancelRunnable;
import com.ly.component.threadpool.callback.SubmitRunnable;

import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

public class SpringTaskManager {
	private final Map<String, Params> threadMap;

	public SpringTaskManager() {
		threadMap = new ConcurrentHashMap<>();
	}

	public static SpringTaskManager getInstance() {
		return Instance.DEFAULT.springTaskManager;
	}

	public boolean submit(
			String name,
			Map<String, Object> params,
			SubmitRunnable runnable,
			CancelRunnable cancelHandle
						 ) {
		if (Objects.nonNull(runnable)) {
			if (!threadMap.containsKey(name)) {
				Thread t = new Thread(() -> {
					boolean flag = false;
					try {
						flag = threadMap.get(name).submitRunnable.run(threadMap.get(name).params);
					} catch (Exception e) {
						e.printStackTrace();
					} finally {
						if (flag) {
							stop(name);
						} else {
							cancel(name);
						}
					}
				});
				Params p = new Params(params, t, runnable, cancelHandle);
				synchronized (threadMap) {
					if (!threadMap.containsKey(name)) {
						threadMap.put(name, p);
						t.start();
						return true;
					}
				}
			}
		}
		return false;
	}

	public boolean cancel(String name) {
		if (Objects.isNull(threadMap.get(name))) {
			return false;
		}
		cancelHandle(name);
		return true;
	}

	public boolean stop(String name) {
		if (Objects.isNull(threadMap.get(name))) {
			return false;
		}
		stopHandle(name);
		return true;
	}

	public boolean isAlive(String name) {
		return threadMap.containsKey(name) && threadMap.get(name).thread.isAlive();
	}

	private void cancelHandle(String name) {
		Params params = threadMap.get(name);
		if (Objects.nonNull(params) && Objects.nonNull(params.cancelRunnable)) {
			Thread t = new Thread(() -> {
				try {
					params.cancelRunnable.run(params.params);
				} catch (Exception e) {
					e.printStackTrace();
				}
			});
			stop(name);
			t.start();
		}
	}

	private void stopHandle(String name) {
		try {
			Params params = null;
			synchronized (threadMap) {
				params = threadMap.remove(name);
			}
			if (Objects.nonNull(params) && params.thread.isAlive()) {
				params.thread.stop();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public void destroy() {
		//关闭线程
		threadMap.forEach((name, thread) -> {
			cancel(name);
			int retry = 0;
			while (!cancel(name) && retry < 2) {
				retry++;
				try {
					Thread.sleep(2000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		});
		int retry = 0;
		while (!threadMap.isEmpty() && retry < 20) {
			retry++;
			try {
				Thread.sleep(2000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	enum Instance {
		DEFAULT(new SpringTaskManager());

		private final SpringTaskManager springTaskManager;

		Instance(SpringTaskManager springTaskManager) {
			this.springTaskManager = springTaskManager;
		}

		public SpringTaskManager instance() {
			return springTaskManager;
		}
	}

	class Params {
		private final Map<String, Object> params;
		private final Thread thread;
		private final SubmitRunnable submitRunnable;
		private final CancelRunnable cancelRunnable;

		public Params(
				Map<String, Object> params,
				Thread thread,
				SubmitRunnable submitRunnable,
				CancelRunnable cancelRunnable
					 ) {
			this.params = params;
			this.thread = thread;
			this.submitRunnable = submitRunnable;
			this.cancelRunnable = cancelRunnable;
		}
	}
}
